home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 10
/
FM Towns Free Software Collection 10.iso
/
ms_dos
/
lib
/
happysrc
/
paasm.c
< prev
next >
Wrap
Text File
|
1994-11-13
|
26KB
|
717 lines
/**********************************************************************
*
* *** HAPPy Pascal Compiler ***
* P-code assmebler
*
* Copyright (c) H.Asano 1992-1994.
*
**********************************************************************/
#define EXTERN extern
#define Maxlabel 500 /* 最大ラベル数 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "version.h"
#include "hapai.h"
/********* co-operation table **********/
static char cop[] = {
115/*lod*/, 105/*ldo*/, 125/*str*/, 120/*sro*/,
130/*sto*/, 110/*chk*/, 135/*ind*/ } ;
/***************************************/
/* ラベル表 */
/***************************************/
enum lbst { entered, /* ラベル未登録の状態 */
defined /* ラベル定義済の状態 */
};
static struct {
short val ; /* value */
enum lbst st ; /* status {enterd,defined} */
} labeltab[Maxlabel] ;
/***************************************/
/* 仮想計算機 記憶装置 */
/***************************************/
static _store store[Maxstore] ;
/***************************************/
/* 変数定義 */
/***************************************/
static char *PcodeSourceName ; /* P-codeソースファイル名 */
static char *PcodeObjectName ; /* P-codeオブジェクトファイル名 */
static char *CompVersion ; /* コンパイラのバージョン */
static FILE *pcsfile ; /* P-codeソースファイルポインタ */
static FILE *objfile ; /* P-codeオブジェクトファイルポインタ */
static short codesize ; /* コードのワードサイズ */
static short objsize ; /* オブジェクト全体のワードサイズ */
static short ch ; /* 読込文字 */
static short intch ; /* 読込処理内での読込文字 */
static short pc ; /* program counter */
static _code cd ; /* P-code */
static short entpc ; /* ent命令の番地 */
static short start = -1 ; /* オブジェクト開始の合図 */
/*********************************************************************/
/***************************************/
/* エラーメッセージ出力処理 */
/***************************************/
static void paerr(short errno)
{
static struct _errmsg {
short msgno ; /* error message number */
char *errmsg ; /* error message */
} errtb[] = {
{1, "命令数が多すぎる"},
{2, "オブジェクトファイルがオープンできない"},
{3, "オブジェクトファイル出力でエラーが発生した"},
{4, "ラベルが多する"},
{5, "定数が多すぎる"},
{6, "P-codeソースファイルがオープンできない"},
{7, "PC.EXEとPA.OVLのバージョンが違う"},
{8, "アセンブルリストの出力でエラーが発生した"}
} ;
short i = -1 ;
while(errtb[++i].msgno != errno) ; /* search message */
fprintf(stderr,"A%03d: %s\n", errno, errtb[i].errmsg);
exit(3) ; /* アセンブルエラーで停止 */
}
/***************************************/
/* reset() : reset関数 */
/***************************************/
static void reset(char *filename)
{
pcsfile = fopen(filename,"r") ;
if(pcsfile == NULL) paerr(6) ;
intch = getc(pcsfile) ; /* 1文字先読み */
}
/***************************************/
/* eoln() : eolnマクロ定義 */
/***************************************/
#define eoln() (intch == '\n') /* 改行を読んでいれば真 */
/***************************************/
/* readc() : char型read処理 */
/***************************************/
static short readc(void)
{
short oldch ;
oldch = intch ;
intch = getc(pcsfile) ;
return(oldch) ;
}
/***************************************/
/* readi() : integer型入力処理 */
/***************************************/
static integer readi(void)
{
integer ival = 0 ;
short sign = 1 ;
if(intch == ' ')
while((intch = getc(pcsfile)) == ' '); /* 空白読み飛ばし */
if(intch=='-') { /* 符号の時 ( + は現れない) */
sign = -1 ; /* 符号に応じた正負 */
intch = getc(pcsfile) ; /* 符号を読み飛ばす */
}
do {
ival = ival*10 + intch-'0' ;
intch=getc(pcsfile) ;
} while(('0' <= intch) && (intch <= '9')) ;
return(sign*ival) ;
}
/***************************************/
/* readr() : real型入力処理 */
/***************************************/
static float readr(void)
{
char buf[20] ;
short i = 0 ;
while(intch == ' ') intch = getc(pcsfile) ; /* 空白読み飛ばし */
do {
buf[i++] = (char)intch ;
intch = getc(pcsfile) ;
} while (intch != '\n') ;
buf[i] = '\0' ;
return((float)atof(buf)) ; /* 浮動小数点へ変換 */
}
/***************************************/
/* readln() : EOLまで読み飛ばす処理 */
/***************************************/
static void readln(void)
{
while(!eoln()) intch = getc(pcsfile) ;
intch = getc(pcsfile);
}
/***************************************/
/* オブジェクトファイル書出処理 */
/***************************************/
static void putobject(char *area, short size)
{
fwrite(area,size,1,objfile) ;
if(ferror(objfile)) paerr(3) ; /* 書き込み失敗 */
}
/***************************************/
/* 初期設定処理 */
/***************************************/
static void init(void)
{
short i;
for(i=0;i<Maxlabel;i++) { /* ラベル表 の 初期設定 */
labeltab[i].val = -1 ;
labeltab[i].st = entered;
}
reset(PcodeSourceName) ; /* P-codeソースファイルのオープン */
objfile = fopen(PcodeObjectName,"wb") ;/* ファイルオープン */
if(objfile == NULL) paerr(2) ; /* オープンできない */
if(codesize > Maxstore) /* 記憶装置の大きさより大きい時*/
paerr(1) ; /* プログラム停止 */
if(strcmp(CompVersion,version))
paerr(7) ; /* バージョン不一致 */
putobject(version,strlen(version)+1) ; /* バージョン番号書出 */
objsize = codesize ;
}
/***************************************/
/* ラベル表登録処理 */
/***************************************/
static void update(void)
{
short x ; /* x: label名 */
short curr,succ ;
x=(short)readi() ; /* ラベル名を読む */
if(x >= Maxlabel) paerr(4) ; /* ラベル数が多すぎる */
if(labeltab[x].val != -1) { /* 前方参照されている時 */
curr = labeltab[x].val;
do {
succ = store[curr].vo.q;
store[curr].vo.q = pc ;
curr = succ ;
} while(succ != -1) ;
}
labeltab[x].st = defined ;
labeltab[x].val = pc ;
}
/***************************************/
/* ラベル値読込処理 */
/***************************************/
static void labelsearch(void)
{
short x ;
while(ch != 'L') ch = readc() ; /* 'L' まで 読み飛ばし */
x = (short)readi() ;
if(x >= Maxlabel) paerr(4) ; /* ラベル数が多すぎる */
if(labeltab[x].st == entered) { /* 未定義 */
cd.q = labeltab[x].val ; /* 初期値のまま -1 */
labeltab[x].val = pc ; /* 今のpcを格納 */
}
else cd.q = labeltab[x].val ; /* 定義済の時 */
}
/********* typesymbol() : instruction名4文字目によってopを決定する *********/
static void typesymbol(void)
{
short i;
switch(ch) {
case 'i' : return ; /* 'i' の時は opはそのまま */
case 'a' : i=0; break;
case 'r' : i=1; break;
case 's' : i=2; break;
case 'b' : i=3; break;
case 'c' : i=4;
}
cd.op=cop[cd.op]+i; /* opの変更 */
}
/**************************************/
/* PTN0() : オペランドのない命令 */
/**************************************/
static void PTN0(void)
{
}
/**************************************/
/* PTN1() : lod,strのアセンブル */
/**************************************/
static void PTN1(void)
{
typesymbol() ;
cd.p=(char)readi() ;
cd.q=(short)readi() ;
}
/**************************************/
/* PTN2() : lda,mov,wrsのアセンブル */
/**************************************/
static void PTN2(void)
{
cd.p=(char)readi() ;
cd.q=(short)readi() ;
}
/*********************************************/
/* PTN3() : mst,cui,bas,tra.mms, */
/* eol,eof,pge,rln,rdc,rdi,rdr,tgt, */
/* tgt,tpt,trs,trw,wln,wrb,wrc,wrf, */
/* wri,wrr のアセンブル */
/*********************************************/
static void PTN3(void)
{
cd.p=(char)readi() ;
}
/**************************************/
/* PTN4() : cup,ejpのアセンブル */
/**************************************/
static void PTN4(void)
{
cd.p=(char)readi() ;
labelsearch();
}
/************************************************/
/* PTN5() : equ,neq,geq,grt,leq,lesのアセンブル */
/************************************************/
static void PTN5(void)
{
switch(ch) {
/*case 'a' : ; break ; 何もしない */
case 'i' : cd.p=1 ; break ;
case 'r' : cd.p=2 ; break ;
case 'b' : cd.p=3 ; break ;
case 's' : cd.p=4 ; break ;
case 'c' : cd.p=6 ; break ;
case 'm' : cd.p=5 ;
cd.q=(short)readi() ;
}
}
/**************************************/
/* PTN6() : ldo,sro,indのアセンブル */
/**************************************/
static void PTN6(void)
{
typesymbol() ;
cd.q=(short)readi();
}
/****************************************/
/* PTN7() : inc,dec,nxt,nxdのアセンブル */
/****************************************/
static void PTN7(void)
{
switch(ch) {
/*case 'a' : cd.p=0; break ; 何もしない */ /* inc,decのみ */
case 'i' : cd.p=1; break ;
case 'b' : cd.p=3; break ;
case 'c' : cd.p=6; break ;
}
cd.q = (short)readi() ;
}
/****************************************/
/* PTN8() : ujp,fjp,lapのアセンブル */
/****************************************/
#define PTN8 labelsearch
/***************************************/
/* PTN9() : lao,new,disのアセンブル */
/***************************************/
static void PTN9(void)
{
cd.q=(short)readi();
}
/**************************************/
/* ENT() : entのアセンブル */
/**************************************/
static void ENT(void)
{
entpc = pc ;
}
/**************************************/
/* CHK() : chkのアセンブル */
/**************************************/
static void CHK(void)
{
integer lb,ub ;
typesymbol() ;
cd.p = (char)readi() ; /* チェック種別 */
lb = readi(); /* 下限値 */
ub = readi(); /* 上限値 */
if(objsize+1>=Maxstore) paerr(5) ; /* 定数格納不可 */
store[objsize ].vi = lb ;
store[objsize+1].vi = ub ;
cd.q=codesize;
do {
cd.q++ ;
} while((store[cd.q-1].vi != lb) || (store[cd.q].vi != ub)) ;
if(cd.q == objsize) objsize++ ;/* 最後に1つだけ定数追加の時 */
if(cd.q-1 == objsize) objsize += 2;/* 最後に2つの 対数追加の時 */
}
/**************************************/
/* IXA() : ixaのアセンブル */
/**************************************/
static void IXA(void)
{
integer low ;
short ixav ;
low = readi() ; /* 下限値 */
ixav = (short)readi() ; /* ixa値 */
if(objsize+1>=Maxstore) paerr(5) ; /* 定数格納不可 */
store[objsize ].vi = low ;
store[objsize+1].va = ixav ; /* 2バイトエリアを使用 */
cd.q=codesize;
do {
cd.q++ ;
} while((store[cd.q-1].vi != low) || (store[cd.q].va != ixav)) ;
if(cd.q == objsize) objsize++ ;/* 最後に1つだけ定数追加の時 */
if(cd.q-1 == objsize) objsize += 2;/* 最後に2つの 対数追加の時 */
}
/**************************************/
/* LCA() : lcaのアセンブル */
/**************************************/
/* lca '文字列'\n という形式とする。最後が改行で終わる。最初の ' と
改行の前の ' は P-codeソースを読む人間にわかりやすいようについているだけ */
static void LCA(void)
{
cd.q=objsize;
readc() ; /* 最初の ' を読み飛ばす */
while(!eoln()) { /* 改行までの文字列を格納 */
if(objsize+1>=Maxstore) paerr(5); /* 定数格納不可 */
store[objsize++].vc = readc() ;
}
objsize-- ; /* 最後の ' を捨てる */
}
/**************************************/
/* checkConst() : 定数格納チェック */
/**************************************/
static void checkConst(void)
{
if(cd.q==objsize) {
if(objsize+1>=Maxstore) paerr(5); /* 定数格納不可 */
objsize++ ;
}
}
/**************************************/
/* LDC() : ldcのアセンブル */
/**************************************/
static void LDC(void)
{
integer inumber ;
float rnumber ;
long s ;
switch(ch) {
case 'i' : cd.p=1 ; /* integer type */
inumber = readi() ;
if(labs(inumber) < (long)Largeint)
cd.q = (short)inumber;
else { /* 大きな数の時 */
cd.op = 66 ; /* lci命令に変更 */
store[objsize].vi = inumber ;
cd.q = codesize ;
while(store[cd.q].vi != inumber) cd.q++ ;
checkConst() ; /* 定数格納チェック */
}
break ;
case 'c' : cd.p=6 ; /* char type */
while(readc() != '\'');/* 最初の ' を見つける */
cd.q=readc() ; /* 文字を読み込む */
break ; /* 最後の ' は無視する */
case 'b' : cd.p=3; /* boolean */
cd.q=(short)readi() ;
break;
case 's' : cd.p = 4; /* set type */
s=0;
while(readc() != '(') ;
while(readc() != ')') addset(s,(short)readi()) ;
store[objsize].vs = s ;
cd.q = codesize ;
while(store[cd.q].vs != s) cd.q++ ;
checkConst() ; /* 定数格納チェック */
break ;
case 'r' : cd.p = 2 ;
rnumber = readr() ;
store[objsize].vr = rnumber ;
inumber = store[objsize].vi ;
/* 浮動小数点の形で比較を行うと思わぬ落とし穴があるので
ビット列の比較をするために、union型のviから数を得る*/
cd.q = codesize ;
while(store[cd.q].vi != inumber) cd.q++ ;
checkConst() ; /* 定数格納チェック */
break ;
/*case 'n' : cd.p=0 ; */ /* ldc nil */
/* cd.q=0 ; */
}
}
/**************************************/
/* ORD() : ordのアセンブル */
/**************************************/
static void ORD(void)
{
switch(ch) {
case 'b' : cd.p=3 ; break ;
case 'c' : cd.p=6 ;
}
}
/**************************************/
/* RET() : retのアセンブル */
/**************************************/
static void RET(void)
{
switch(ch) {
/*case 'p' : ; break ; 何もしない */
case 'i' : cd.p=1 ; break ;
case 'r' : cd.p=2 ; break ;
case 'c' : cd.p=3 ; break ;
case 'b' : cd.p=4 ; break ;
case 'a' : cd.p=5 ; break ;
}
}
/**************************************/
/* STO() : stoのアセンブル */
/**************************************/
#define STO typesymbol
/**********************************************************************/
/* P-code ニーモニック表 */
/**********************************************************************/
static char instr[][4] =
{
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 */
/* 0x */ "lod","ldo","str","sro","sto","chk","ind","ldc","lda","dec",
/* 1x */ "inc","mst","cup","ent","ret","...","ixa","equ","neq","geq",
/* 2x */ "grt","leq","les","ujp","fjp","xjp","ejp","lap","adi","adr",
/* 3x */ "sbi","sbr","sgs","flt","flo","trc","ngi","ngr","sqi","sqr",
/* 4x */ "abi","abr","not","and","ior","dif","int","uni","inn","mod",
/* 5x */ "odd","mpi","mpr","dvi","dvr","mov","lca","lao","stp","ord",
/* 6x */ "chr","ujc","mms","msi","cui","bas","...","cka","tra","rou",
/* 7x */ "nxt","nxd","...","...","...","new","dis","pge","eof","eol",
/* 8x */ "rst","rwt","get","put","wrs","wrb","wri","wrr","wrc","wrf",
/* 9x */ "wln","rdi","rdr","rdc","rln","trs","trw","tgt","tpt","atn",
/*10x */ "sin","cos","exp","log","sqt"
} ;
/******* ニーモニック対応のエントリ表 ********/
static struct entry {
void (*func)(void) ;
} OP[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 */
/* 0x */ PTN1, PTN6 ,PTN1, PTN6, STO , CHK , PTN6, LDC , PTN2, PTN7,
/* 1x */ PTN7, PTN3, PTN4, ENT , RET , PTN0, IXA , PTN5, PTN5, PTN5,
/* 2x */ PTN5, PTN5, PTN5, PTN8, PTN8, PTN0, PTN4, PTN8, PTN0, PTN0,
/* 3x */ PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0,
/* 4x */ PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0,
/* 5x */ PTN0, PTN0, PTN0, PTN0, PTN0, PTN2, LCA , PTN9, PTN0, ORD ,
/* 6x */ PTN0, PTN0, PTN3, PTN0, PTN3, PTN3, PTN0, PTN0, PTN3, PTN0,
/* 7x */ PTN7, PTN7, PTN0, PTN0, PTN0, PTN9, PTN9, PTN3, PTN3, PTN3,
/* 8x */ PTN0, PTN0, PTN0, PTN0, PTN2, PTN3, PTN3, PTN3, PTN3, PTN3,
/* 9x */ PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN0,
/*10x */ PTN0, PTN0, PTN0, PTN0, PTN0
} ;
/***************************************/
/* 1行アセンブル処理 */
/***************************************/
static void assemble(void)
{
char name[4];
*name = (char)readc() ; /* 1文字目 */
*(name+1) = (char)readc() ; /* 2文字目 */
*(name+2) = (char)readc() ; /* 3文字目 */
*(name+3) = '\0' ;
if(!eoln()) ch=readc();
/* そこで行が終わってなければ次の文字を読む */
cd.op = -1 ;
while(strcmp(instr[++cd.op],name)) ;/* instructionよりopを決定 */
/* このようなリニアサーチはスピードが遅いので改良しよう */
cd.p = 0 ;
cd.q = 0 ;
OP[cd.op].func() ; /* opに対応したアセンブル */
store[pc++].vo = cd ; /* メモリに格納 */
}
/********** generate() : 行の最初に呼ばれる処理 **********/
static void generate(void)
{
short i ; /* 作業カウンタ */
char progname[33] ; /* プログラム名 */
char filename[33] ; /* ファイル名 */
short fileadr ; /* ファイルアトレス */
short filesize ; /* バッファ変数の大きさ */
for(;;) {
ch=readc(); /* 行の最初の文字を読む */
switch(ch) {
case ' ' : assemble(); /* 通常命令 その行をアセンブル*/
break ;
case ';' : /* 注釈行を無視 */
break ;
case 'L' : update() ; /* label登録 */
break ;
case 'V' : store[entpc].vo.p = (unsigned char)readi() ;
store[entpc].vo.q = (short) readi() ;
break ;
case 'F' : /* ファイルアドレス */
readc() ; /* 空白を読み飛ばす */
i=0 ;
while((ch=readc()) != ' ') /* ファイル名取得 */
filename[i++] = (char)ch ;
filename[i++] = '\0' ;
readc() ; /* 空白を読み飛ばす*/
fileadr = (short)readi() ; /* ファイルアトレス */
putobject((char*)&fileadr,sizeof(fileadr));/* 書出 */
filesize = (short)readi(); /* バッファサイズ */
putobject((char*)&filesize,sizeof(filesize));/* 書出*/
putobject(filename,i) ; /* ファイル名書出 */
break ;
case 'N' : /* プログラム名 */
readc() ; /* 空白を読み飛ばす */
i=0 ;
while(!eoln()) /* プログラム名取得 */
progname[i++] = (char)readc() ;
progname[i++] = '\0' ;
putobject(progname,i);/* 書出 */
break ;
case 'Q' : return ; /* アセンブル終わり */
}
readln() ; /* 行の残りを読み飛ばし */
}
}
/*****************************************/
/* assemblelist() : アセンブルリスト出力 */
/*****************************************/
static void assemblelist(void)
{
reset(PcodeSourceName) ; /* P-codeソースファイルのオープン */
printf("\n ADDR OP P Q P-code source statement\n");
printf( "================================================\n");
pc = 0 ;
for(;;) {
ch=readc(); /* 行の最初の文字 */
switch(ch) {
case ' ' : printf(" %4d: %3d %3d %6d %c",
pc++, store[pc].vo.op, store[pc].vo.p ,
store[pc].vo.q,ch);
break;
case ';' :
case 'L' :
case 'V' :
case 'F' :
case 'N' : printf("\t\t\t %c",ch) ;
break;
case 'Q' : printf("\t\t\t Q\n") ;
if(codesize != objsize)
printf(" %4d:\n ~: constant data\n %4d:\n",
codesize,objsize-1) ;
fclose(pcsfile) ; /* ソースファイルのクローズ */
return;
}
while(!eoln()) putc(readc(),stdout) ;
printf("\n") ;
if(ferror(stdout)) paerr(8) ; /* 出力でエラーが発生した */
readln() ;
}
}
/***************************************/
/* main() : P-codeアセンブラメイン処理 */
/***************************************/
short main(short argc,char *argv[])
{
codesize = atoi(argv[1]) ; /* 命令コードの数 */
PcodeSourceName = argv[2] ; /* P-codeソースファイル名 */
PcodeObjectName = argv[3] ; /* P-codeオブジェクトファイル名*/
CompVersion = argv[4] ; /* コンパイラのバージョン */
init(); /* 各種初期設定 */
generate(); /* アセンブル */
fclose(pcsfile) ; /* ソースファイルのクローズ */
for(pc=0;pc<codesize;pc++) { /* qオペランドの補正処理 */
cd.op = store[pc].vo.op ;
if((/*lao*/ cd.op==57)||(/*ldox*/cd.op==1 || (105<=cd.op && cd.op<=109))
||(/*srox*/cd.op==3 || (120<=cd.op && cd.op<=124)))
store[pc].vo.q += objsize ;
}
putobject((char*)&start,sizeof(start)) ; /* オブジェクト開始合図 */
putobject((char*)store,objsize*sizeof(_store)) ; /* オブジェクト出力*/
if(fflush(objfile) == EOF) paerr(3) ;
if(fclose(objfile) == EOF) paerr(3) ;
/* クローズできなければ書き込み失敗の可能性がある */
fputs( " *** Assemble completed. ***\n",stderr);
fprintf(stderr," *** code = %5d words constant data = %5d words ***\n",
codesize, objsize-codesize);
if(argc==6) assemblelist(); /* アセンブルリストの出力 */
return(0) ; /* 正常終了 */
}